﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BackupAssurance.Library.MEF;
using System.ComponentModel.Composition;
using BackupAssurance.Library.ModelsDB;
using BackupAssurance.Library.Interfaces;
using BackupAssurance.Library.XML;
using BackupAssurance.Library.Constants;
using System.IO;
using BackupAssurance.Library.Enums;

namespace BackupAssurance.impVerifyFileExists
{
    //<resource key="_ProcessFolder">m:\</resource><resource key="_NumHoursBack">30</resource><resource key="INCLUDEPATHSNFILENAMES">*app2\daily*|*app2_backup*|bak;*app3db\daily*|*app2_backup*|bak;*app3db\daily\app4*|*app4_backup*|dif;*app3db\daily\app3*|*app3_backup*|dif;*medb\daily\performance*|*performance_backup*|DIF;*app3db\daily\portal*|*portal_backup*|DIF;*app5\daily*|*app5*|TRN;*svn\tmp*|*app6*|zip;*svn\tmp*|*cod-*|zip;*svn\tmp*|*app7*|zip;*svn\tmp*|*app3-*|zip;*svn\tmp*|*app8*|zip;*svn\tmp*|*app9*|zip;*Application\daily\bak*|Application Daily|BAK</resource>

    //<resource key="_ProcessFolder">m:\</resource><resource key="_NumHoursBack">30</resource><resource key="INCLUDEPATHSNFILENAMES">*app2\weekly*|*app2_backup*|bak;*app3db\weekly*|*app2_backup*|bak;*app3db\weekly\app4*|*app4_backup*|dif;*app3db\weekly\app3*|*app3_backup*|dif;*app3db\weekly\performance*|*performance_backup*|DIF;*app3db\weekly\portal*|*portal_backup*|DIF;*app5\weekly*|*app5*|TRN;*svn\tmp*|*app6*|zip;*svn\tmp*|*cod-*|zip;*svn\tmp*|*app7*|zip;*svn\tmp*|*app3-*|zip;*svn\tmp*|*app8*|zip;*svn\tmp*|*app9*|zip;*Application\weekly\bak*|Application weekly|BAK</resource>


    [Export(typeof(IExecute)), ExportMetadata("PlugInType", "VerifyFileExists"), ExportMetadata("Version", 1)]
    public class piVerifyFileExists : IExecute
    {
        [Import]
        public IfLogger objLog { get; set; }

        string _name = null;
        int _NumHoursBack = 0;
        string IncludePathsNFilenames = "";
        string _ProcessFolder;
        int _NumFilesNotCreated;
        StringBuilder objstring;
        //Boolean _bMissingFiles;
        int _NumFilesToVerify;

        List<filestructure> _objCleanedMasks;
        //List<string> objFilesNotCreated = new List<string>();

        private void ProcessFile(FileInfo file, pcPlugInValue plugininfo)
        {

            //check if the current file matches any of the patterns sought
            foreach (filestructure objcleanedmask in _objCleanedMasks)
            {
                if (objcleanedmask.FileMatchesPattern(_ProcessFolder, file))
                {
                    //this file is one of the ones we want.  Now check its age.
                    //now check how old the file is:
                    TimeSpan span = DateTime.Now - file.LastWriteTime;// .LastAccessTime;
                    double HoursOld = span.TotalHours;
                    if (HoursOld <= _NumHoursBack)
                    {
                        objcleanedmask.wasfilefound = true;
                        _NumFilesToVerify = _NumFilesToVerify + 1;
                        string output = String.Format("File Found: [{0}], Pattern: [{1}], [{2:0.00}] hours old and last created [{3}]", file.FullName, objcleanedmask._OriginalPattern, HoursOld, file.LastWriteTime.ToString());
                        objstring.AppendLine(output);
                    }
                }
            }

        }

        public string Execute(pcJobAction jobaction, pcPlugInValue plugininfo)
        {
            //dimention objects
            string strResult = "";
            _ProcessFolder = "";
            string[] aIncludePathsNFilenames;
            filestructure objfilestructure;
            objstring = new StringBuilder();
            _objCleanedMasks = new List<filestructure>();
            string output;
            _NumFilesNotCreated = 0;
            _NumFilesToVerify = 0;
            //_bMissingFiles = false;

            _name = " START, Computer:" + System.Environment.MachineName + " VerifyFileExists v1,  Job ID:" + jobaction.Id.ToString() + " Plugin ID:" + plugininfo.Id.ToString() + Environment.NewLine + "       [" + plugininfo.PlugInText + "]";

            objstring.AppendLine("");
            objstring.AppendLine("");
            objstring.AppendLine("New files created as of [" + DateTime.Now + "]");
            objstring.AppendLine("--------------------------------------------------");
            try
            {
                //grab the fields from the XML or whatever.
                Dictionary<string, string> objDic;
                objLog.WriteLine("Plugin Start: " + _name);
                objDic = fXMLParser.ConvertXMLtoDictionary(plugininfo.PlugInText);
                _ProcessFolder = objDic[Constants.PLG_PROCESSFOLDER];
                _NumHoursBack = Int32.Parse(objDic[Constants.PLG_NUMHOURSBACK]);
                IncludePathsNFilenames = objDic[Constants.PLG_INCLUDEPATHSNFILENAMES];
                IncludePathsNFilenames = IncludePathsNFilenames.Trim().ToUpper();
                _ProcessFolder = _ProcessFolder.Trim().ToUpper();

                if (_ProcessFolder.Substring(_ProcessFolder.Length - 1, 1) != "\\")
                {
                    _ProcessFolder = _ProcessFolder + "\\";
                }

                //verify the input
                if (IncludePathsNFilenames == "")
                {
                    output = _name + Environment.NewLine + " The IncludePathsNFileNames field was not specified in the XML of the PlugInText field; the field needs to include the folder|filename|extensions sought.  Multiple entries can be separated with a semicolon ; and fields can be separated with pipe | ";
                    objLog.WriteError(0, output);
                    throw new Exception(output);
                }

                //process the [IncludePathsNFilenames] field
                aIncludePathsNFilenames = IncludePathsNFilenames.Split(';');
                int numsearchpatterns = aIncludePathsNFilenames.Length;

                //convert the contents of the [IncludePathsNFilenames] field into objects, then add them to a list
                try
                {
                    foreach (string filenamegroup in aIncludePathsNFilenames)
                    {
                        objfilestructure = new filestructure();
                        if (filenamegroup == "")
                        {
                            //ignore this entry
                            objLog.WriteLine("File mask was empty and it will be skipped.");
                        }
                        else
                        {
                            objfilestructure.init(filenamegroup);
                            _objCleanedMasks.Add(objfilestructure);
                        }
                    }
                }
                catch (Exception ex)
                {
                    output = "There was an issue trying to parse and process the IncludePathsNFileNames field.  " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace;
                    objLog.WriteError(0, output);
                    throw new Exception(output);
                }

                //check if the _ProcessFolder exists
                try
                {

                    if (!Directory.Exists(_ProcessFolder))
                    {
                        output = _name + Environment.NewLine + "Process Folder [" + _ProcessFolder + "] does not exist.";
                        objLog.WriteError(0, output);
                        throw new Exception(output);
                    }
                }
                catch (Exception)
                {
                    output = _name + Environment.NewLine + "Process Folder [" + _ProcessFolder + "] does not exist.";
                    objLog.WriteError(0, output);
                    throw new Exception(output);
                }


                // finally, read the contents of the process folder and see which files match the criteria
                try
                {
                    //ok, start to look for files/folders to delete
                    objLog.WriteLine("Verifying that the new files were created...");
                    DirectoryInfo di = new DirectoryInfo(_ProcessFolder);
                    WalkDirectoryTree(di, plugininfo);
                }
                catch (Exception e)
                {
                    output = _name + Environment.NewLine + " Unhandled Error trying to verify that the new files were created." + Environment.NewLine + e.Message + Environment.NewLine + e.StackTrace;
                    objLog.WriteError(0, output);
                    throw new Exception(output);
                }

                _NumFilesNotCreated = 0;
                foreach (filestructure objcleanedmask in _objCleanedMasks)
                {
                    if (objcleanedmask.wasfilefound == false)
                    {
                        _NumFilesNotCreated = _NumFilesNotCreated + 1;
                    }
                }

                if (_NumFilesNotCreated >= 1)
                {
                    objstring.AppendLine("");
                    objstring.AppendLine("");
                    objstring.AppendLine("*ISSUE* Files Not Found");
                    objstring.AppendLine("--------------------------------------------------");

                    foreach (filestructure objcleanedmask in _objCleanedMasks)
                    {
                        if (objcleanedmask.wasfilefound == false)
                        {
                            objstring.AppendLine("File Missing.  Pattern: [" + objcleanedmask._OriginalPattern + "]");
                        }
                    }

                }

                objstring.AppendLine("");
                objstring.AppendLine("");
                objstring.AppendLine("Totals");
                objstring.AppendLine("--------------------------------------------------");
                objstring.AppendLine("Files Verified:" + _NumFilesToVerify.ToString());
                objstring.AppendLine("Files Missing:" + _NumFilesNotCreated.ToString());
                objstring.AppendLine("");
                objstring.AppendLine("");
                objstring.AppendLine("--------------------------------------------------");
                objstring.AppendLine(_name);

                strResult = objstring.ToString();
            }
            catch (Exception ex)
            {
                output = _name + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace;
                objLog.WriteError(0, output);
                throw new Exception(output);

            }

            return strResult;

        }






        void WalkDirectoryTree(System.IO.DirectoryInfo root, pcPlugInValue plugininfo)
        {
            string output;
            System.IO.FileInfo[] files = null;
            System.IO.DirectoryInfo[] subDirs = null;

            // First, process all the files directly under this folder
            try
            {
                files = root.GetFiles("*.*");
            }
            // This is thrown if even one of the files requires permissions greater
            // than the application provides.
            catch (UnauthorizedAccessException e)
            {
                // This code just writes out the message and continues to recurse.
                // You may decide to do something different here. For example, you
                // can try to elevate your privileges and access the file again.
                output = _name + Environment.NewLine + " Error:Unauthorized Access.  " + root.ToString() + e.Message + Environment.NewLine + " StackTrace:" + e.StackTrace;
                objLog.WriteError(0, output);
            }

            catch (System.IO.DirectoryNotFoundException e)
            {
                output = _name + Environment.NewLine + " Error:Directory Not Found.  " + root.ToString() + e.Message + Environment.NewLine + " StackTrace:" + e.StackTrace;
                objLog.WriteError(0, output);
            }

            if (files != null)
            {
                foreach (System.IO.FileInfo fi in files)
                {
                    // In this example, we only access the existing FileInfo object. If we
                    // want to open, delete or modify the file, then
                    // a try-catch block is required here to handle the case
                    // where the file has been deleted since the call to TraverseTree().

                    try
                    {
                        ProcessFile(fi, plugininfo);

                    }
                    catch (Exception e)
                    {
                        output = _name + Environment.NewLine + " Unhandled Error Professing File  [" + fi.FullName + "] " + Environment.NewLine + e.Message + Environment.NewLine + " StackTrace:" + e.StackTrace;
                        objLog.WriteError(0, output);
                        //throw new Exception(output);
                    }
                }

                // Now find all the subdirectories under this directory.
                subDirs = root.GetDirectories();
                foreach (System.IO.DirectoryInfo dirInfo in subDirs)
                {
                    // Resursive call for each subdirectory.
                    WalkDirectoryTree(dirInfo, plugininfo);
                }

            }
        }

        public bool IsDirectoryEmpty(string path)
        {
            return !Directory.EnumerateFileSystemEntries(path).Any();
        }

        public void Dispose()
        {

        }

    }
}
